/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package desu.nya.DAO;

import desu.db.HibernateUtil;
import desu.nya.*;
import java.io.ByteArrayInputStream;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;

/**
 *
 * @author Fess
 */
public class AnimeIMPL implements AnimeDAO{

    @Override
    public void addAnime(Anime anime) throws SQLException {
        Session session=null;
        try{
            session=HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();
            session.save(anime.getCover());
            session.save(anime);
            session.getTransaction().commit();
        }
        catch(Exception ex){
            System.err.println("HiB: Anime insert error");
        }
        finally{
            if(session!=null&&session.isOpen())
                session.close();
        }
    }

    @Override
    public Anime getAnimeByID(Long id) throws SQLException {
        Session session=null;
        Anime anime=null;
        try{
            session=HibernateUtil.getSessionFactory().openSession();
            anime=(Anime)session.load(Anime.class, id);
        }
        catch(Exception ex){
            System.err.println("HiB: Anime search error");
        }
        finally{
            if(session!=null&&session.isOpen())
                session.close();
        }
        return anime;
    }

    @Override
    public void updateAnime(Long anime_id, Anime anime) throws SQLException {
        Session session=null;
        try{
            session=HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();
            session.update(anime);
            session.getTransaction().commit();
        }
        catch(Exception ex){
            System.err.println("HiB: Anime update fail");
        }
        finally{
            if(session!=null&&session.isOpen())
                session.close();
        }
    }

    @Override
    public List<Anime> getAllAnime() throws SQLException {
//        if(session!=null&&session.isOpen())
//                session.close();
        Session session=null;
        List<Anime> list=null;
        try{
                session=HibernateUtil.getSessionFactory().openSession();
            list=(List<Anime>)session.createCriteria(Anime.class).list();
        }
        catch(Exception ex){
            System.err.println("HiB: Anime get error");
        }
        finally{
            if(session!=null&&session.isOpen())
                session.close();
        }
        return list;
    }

    @Override
    public void deleteAnime(Anime anime) throws SQLException {
        Session session=null;
        try{
            session=HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();
            session.delete(anime);
            session.getTransaction().commit();
        }
        catch(Exception ex){
            System.err.println("HiB: Anime delete error");
        }
        finally{
            if(session!=null&&session.isOpen())
                session.close();
        }
    }

    @Override
    public StreamedContent getCoverStream(Long id) throws SQLException {
        Session session=null;
        StreamedContent animeImg=null;
        try{
            session=HibernateUtil.getSessionFactory().openSession();
            Cover cover=(Cover)session.load(Cover.class, id);
            animeImg=new DefaultStreamedContent(new ByteArrayInputStream(cover.getImage()), "image/jpg");
        }
        catch(Exception ex){
            System.err.println("HiB: Anime delete error");
        }
        finally{
            if(session!=null&&session.isOpen())
                session.close();
        }
        return animeImg;
    }

    @Override
    public List<Anime> getAnimeTop(int count, String genre) throws SQLException {
        Session session=null;
        List<Anime> list=null;
        try{
            session=HibernateUtil.getSessionFactory().openSession();
            Criteria cr=session.createCriteria(Anime.class).addOrder(Order.desc("avgRate"));
            cr.setMaxResults(count);
            list=cr.list();
            System.out.println("HiB: Ordered Top Anime Founded: "+list.size());
        }
        catch(Exception ex){
            System.err.println("HiB: AnimeTop get error");
        }
        finally{
            if(session!=null&&session.isOpen())
                session.close();
        }
        return list;
    }

    @Override
    public List<Anime> getAnimeWithFilter(String name, Long studioId, Long typeEdId, Long genreId, Long exGenreId, int year,int resultSize) throws SQLException {
        Session session=null;
        if(genreId==exGenreId)exGenreId=null;
        List<Anime> list=null;
        try{
            session=HibernateUtil.getSessionFactory().openSession();
            String hql;
            boolean fl=false;
//            if(genre==null&&exGenre==null){
//                Criteria cr=null;
//                cr=session.createCriteria(Anime.class);
//                if(studio!=null)
//                    cr.add(Expression.eq("studio", studio));
//                if(typeEd!=null)
//                    cr.add(Expression.eq("typeEd", typeEd));
//                list=(List<Anime>)cr.list();
                hql="select animeId from GenreList gl";
                Studio studio=null;
                TypeEd typeEd=null;
                Genre genre=null;
                Genre exGenre=null;
                if(studioId!=null&&studioId>0)
                    studio=(Studio)session.load(Studio.class, studioId);
                if(typeEdId!=null&&typeEdId>0)
                    typeEd=(TypeEd)session.load(TypeEd.class, typeEdId);
                if(genreId!=null&&genreId>0)
                    genre=(Genre)session.load(Genre.class, genreId);
                if(exGenreId!=null&&exGenreId>0)
                    exGenre=(Genre)session.load(Genre.class, exGenreId);
                if(name!=null||studio!=null||typeEd!=null||genre!=null||exGenre!=null||year!=-1)
                    hql+=" where ";
                if(studio!=null){
                    hql+="gl.animeId.studio=:st ";
                    fl=true;
                }
                if(name!=null){
                    hql+=fl?"AND ":"";
                    hql+="gl.animeId.name like '%"+name+"%' ";
                    fl=true;
                }
                if(year!=-1){
                    hql+=fl?"AND ":"";
                    hql+="gl.animeId.dateOp >= '"+String.valueOf(year)+"-01-01' AND gl.animeId.dateOp <'"+String.valueOf(year+1) +"-01-01' ";
                    fl=true;
                }
                if(typeEd!=null){
                    hql+=fl?"AND gl.animeId.typeEd=:te ":"gl.animeId.typeEd=:te ";
                    fl=true;
                }
                if(genre!=null&&exGenre!=null)
                    hql+=fl?"AND (gl.genreId=:genre OR gl.genreId=:exGenre)":"(gl.genreId=:genre OR gl.genreId=:exGenre)";
                if(genre!=null&&exGenre==null)
                        hql+=fl?"AND gl.genreId=:genre":"gl.genreId=:genre";
                if(genre==null&&exGenre!=null)
                        hql+=fl?"AND gl.genreId=:exGenre":"gl.genreId=:exGenre";
                hql+=" group by gl.animeId";
                if(genre!=null&&exGenre!=null)
                    hql+=" having count(*)>1";
                Query query=session.createQuery(hql);
                
                if(genre!=null)
                    query.setEntity("genre", genre);
                if(exGenre!=null)
                    query.setEntity("exGenre", exGenre);
                if(studio!=null)
                    query.setEntity("st", studio);
                if(typeEd!=null)
                    query.setEntity("te", typeEd);
//                if(name!=null)
//                    query.setEntity("name", name);
                query.setMaxResults(resultSize);
                list=(List<Anime>)query.list();
//            }
//            else {
//                hql="select animeId from GenreList gl where ";
//                if(genre!=null&&exGenre!=null)
//                    hql+="gl.genreId=:genre OR gl.genreId=:exGenre";
//                else
//                    if(genre!=null)
//                        hql+="gl.genreId=:genre";
//                    else
//                        hql+="gl.genreId=:exGenre";
//                Query query =session.createQuery(hql);
//                if(genre!=null)
//                    query.setEntity("genre", genre);
//                if(exGenre!=null)
//                    query.setEntity("exGenre", exGenre);
//                list=(List<Anime>)query.list();
               
//                Criteria cr=session.createCriteria(GenreList.class);
//                if(genre!=null&&exGenre!=null)
//                    cr.add(Expression.or(Expression.eq("genreId", genre), Expression.eq("genreId", exGenre)));
//                else
//                    cr.add(Expression.eq("genreId", genre!=null?genre:exGenre));
//                GenreList gl=new GenreList();
//                cr.createCriteria("animeId");
//                list=(List<Anime>)cr.list();
//                int size=list.size();
                
//            }
            
            System.out.println("HiB: Filtered Anime Founded: "+list.size());
        }
        catch(Exception ex){
            ex.printStackTrace();
            System.err.println("HiB: AnimeFilter get error");
        }
        finally{
            if(session!=null&&session.isOpen())
                session.close();
        }
        return list;
    }

    @Override
    public List<Anime> getOngoings() throws SQLException {
        Session session=null;
        List<Anime> list=null;
        Calendar cal=Calendar.getInstance();
        cal.setTime(new Date());
        Date dt=new Date();
        try{
            session=HibernateUtil.getSessionFactory().openSession();
            TypeEd tv,ona,ova;
            tv=(TypeEd)session.load(TypeEd.class, 1l);
            ova=(TypeEd)session.load(TypeEd.class, 2l);
            ona=(TypeEd)session.load(TypeEd.class, 3l);
            Criteria cr=session.createCriteria(Anime.class);
            cr.add(Expression.and(
                    Expression.gt("dateOp", dt),
                    Expression.or(
                        Expression.lt("dateEnd", dt), Expression.eq("dateEnd", null))));
            cr.add(Expression.or(Expression.eq("typeEd", tv),
                    Expression.or(Expression.eq("typeEd", ova), Expression.eq("typeEd", ona))));
            list=(List<Anime>)cr.list();
            System.out.println("HiB: Ongoing Founded: "+list.size());
        }
        catch(Exception ex){
            ex.printStackTrace();
            System.err.println("HiB: Ongoing search fail");
        }
        finally{
            if(session!=null&&session.isOpen())
                session.close();
        }
        return list;
    }

    @Override
    public Rating getRating(Long animeId, String otakuNick) throws SQLException {
        Session session=null;
        Rating rate=null;
        try{
            session=HibernateUtil.getSessionFactory().openSession();
            String hql="from Rating where anime.id=:animeId and otaku.nickname=:nick";
//            Criteria cr=session.createCriteria(Rating.class);
//            cr.add(Expression.eq("anime.id", animeId)).add(Expression.eq("otaku.nickname", otakuNick)).setMaxResults(1);
            Query query=session.createQuery(hql);
            query.setLong("animeId", animeId).setString("nick", otakuNick);
            List<Rating> list=query.list();
            if(list.isEmpty()){
                rate=new Rating();
                Anime anime=(Anime)session.load(Anime.class, animeId);
                Otaku otaku=(Otaku)session.createCriteria(Otaku.class).add(Expression.eq("nickname", otakuNick)).list().get(0);
                rate.setAnime(anime);
                rate.setOtaku(otaku);
                rate.setRate(-1);
                session.beginTransaction();
                session.save(rate);
                session.getTransaction().commit();
//                rate.se
            }
            else
                rate=list.get(0);
            if(rate.getRate()==null)rate.setRate(-1);
        }
        catch(Exception ex){
            ex.printStackTrace();
            System.err.println("HiB: Rate search error");
        }
        finally{
            if(session!=null&&session.isOpen())
                session.close();
        }
        return rate;
    }

    @Override
    public Anime createAnimeWithStr(String name, Long typeEd, String chapter, int countOfSer, int duration, String director, Long studio, Long cover, String href) {
        Session session=null;
        Rating rate=null;
        Anime anime=null;
        try{
            session=HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();
            TypeEd te=null;
            Studio st=null;
            Cover cv=null;
            if(typeEd!=null)
                te=(TypeEd)session.load(TypeEd.class, typeEd);
            if(studio!=null)
                st=(Studio)session.load(Studio.class, studio);
            if(cover!=null)
                cv=(Cover)session.load(Cover.class, cover);
            anime=new Anime(name, te, chapter, countOfSer, duration, director, st, cv, href);
//            session.save(anime);
            session.getTransaction().commit();
        }
        catch(Exception ex){
            ex.printStackTrace();
            System.err.println("HiB: Create anime error");
        }
        finally{
            if(session!=null&&session.isOpen())
                session.close();
        }
        return anime;
    }
    
    
    private void avgRateRefresh(Anime anime){
        Session session=null;
        try{
            if(session==null)
                session=HibernateUtil.getSessionFactory().openSession();
            Criteria cr=session.createCriteria(Rating.class);
            cr.add(Expression.eq("anime", anime)).add(Expression.gt("rate",0)).setProjection(Projections.avg("rate"));
            double s=(Double)cr.list().get(0);
            session.beginTransaction();
            anime.setAvgRate(s);
            session.update(anime);
            session.getTransaction().commit();
        }
        catch(Exception ex){
            System.err.println("HiB: Rating update fail");
        }
        finally{
            if(session!=null&&session.isOpen())
                session.close();
        }
    }

    @Override
    public boolean isExistByHref(Long href) throws SQLException {
        Session session=null;
        List list=null;
        boolean retBool=false;
        try{
            session=HibernateUtil.getSessionFactory().openSession();
            list=session.createCriteria(Anime.class).add(Expression.eq("href", href.toString())).list();
            retBool=list.size()>0;
        }
        catch(Exception ex){
            System.err.println("HiB: Anime search error");
        }
        finally{
            if(session!=null&&session.isOpen())
                session.close();
        }
        return retBool;
    }

    @Override
    public int altNameCheck() throws SQLException {
        Session session=null;
        List<Anime> list=null;
        int count=-1;
        try{
            session=HibernateUtil.getSessionFactory().openSession();
            Criteria cr=session.createCriteria(Anime.class);
            list =cr.list();
            count=list.size();
            session.beginTransaction();
            for(Anime an:list){
                String str=an.getName();
                an.setAltName(new AltName(str, str, str));
                session.save(an);
            }
            session.getTransaction().commit();
        }
        catch(Exception ex){
            System.err.println("HiB: Anime name check error");
        }
        finally{
            if(session!=null&&session.isOpen())
                session.close();
        }
        return count;
    }
}
